package ao.ai.ml.algo.supervised.classification.linear.discriminative.glm;

import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;

/**
 * User: aostrovsky
 * Date: 20-Feb-2010
 * Time: 1:47:12 PM
 */
public class ExponentialFamily
{
    //-------------------------------------------------------------------------
    public static final UnivariateRealFunction
            UNIT_SUFFICIENT_STATISTIC = new UnivariateRealFunction() {
        @Override public double value(
                double independent) throws FunctionEvaluationException {
            return independent;
        }
    };

    public static final UnivariateRealFunction
            BERNULI_PARAMETER = new UnivariateRealFunction() {
        @Override public double value(
                double eta) throws FunctionEvaluationException {
            return Math.log(eta / (1.0 - eta));
        }
    };

//    public static final UnivariateRealFunction
//            PHI = new UnivariateRealFunction() {
//        @Override public double value(
//                double eta) throws FunctionEvaluationException {
//            return 1.0 / (1 + Math.exp(-eta));
//        }
//    };

    public static final UnivariateRealFunction
            BERNULI_A = new UnivariateRealFunction() {
        @Override public double value(
                double eta) throws FunctionEvaluationException {
            return Math.log(1.0 - Math.exp(eta));
        }
    };

    public static final UnivariateRealFunction
            UNIT_B = new UnivariateRealFunction() {
        @Override public double value(
                double independent) throws FunctionEvaluationException {
            return 1.0;
        }
    };


    //-------------------------------------------------------------------------
    public static void main(String[] args)
            throws FunctionEvaluationException
    {
        ExponentialFamily family =
                new ExponentialFamily(
                        BERNULI_A,
                        UNIT_B,
                        UNIT_SUFFICIENT_STATISTIC);
        
        UnivariateRealFunction logistic =
//                family.member(BERNULI_PARAMETER);
                family.member(0.5);

        System.out.println(
                logistic.value( 0 ));
        System.out.println(
                logistic.value( 1 ));

//        for (double i = -10; i <= 10; i++)
//        {
//            System.out.println(
//                    i + " = " +
//                    logistic.value( i ));
//        }
    }


    //-------------------------------------------------------------------------
    private final UnivariateRealFunction a;
    private final UnivariateRealFunction b;
    private final UnivariateRealFunction sufficientStatistic;


    //-------------------------------------------------------------------------
    public ExponentialFamily(
            UnivariateRealFunction a,
            UnivariateRealFunction b,
            UnivariateRealFunction sufficientStatistic)
    {
        this.a = a;
        this.b = b;

        this.sufficientStatistic = sufficientStatistic;
    }


    //-------------------------------------------------------------------------
    public UnivariateRealFunction member(
            //final UnivariateRealFunction naturalParameter)
            final double naturalParameter)
    {
        return new UnivariateRealFunction() {
            @Override public double value(double y)
                    throws FunctionEvaluationException,
                           IllegalArgumentException
            {
                return b.value( y ) *
                       Math.exp(
                           naturalParameter *
                           sufficientStatistic.value(y) -
                           a.value(naturalParameter));
            }
        };
    }




    //-------------------------------------------------------------------------



}
